package gitee.derumin.lifeissohard.mixin;


import gitee.derumin.lifeissohard.effects.LishStatusEffects;
import gitee.derumin.lifeissohard.lishhungersystem.LishHungerManager;
import gitee.derumin.lifeissohard.tools.PlayerEntityTools;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.damage.DamageTracker;
import net.minecraft.entity.damage.EntityDamageSource;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.player.*;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Objects;


@Mixin(PlayerEntity.class)
public abstract class PlayerEntityMixin extends LivingEntity implements PlayerEntityTools {


    @Shadow public abstract boolean damage(DamageSource source, float amount);

    @Shadow
    protected HungerManager hungerManager;
    @Final
    @Shadow
    private final PlayerAbilities abilities = new PlayerAbilities();


    @Shadow public abstract HungerManager getHungerManager();

    public PlayerEntityMixin(World world) {
        super(EntityType.PLAYER, world);
    }

    public void setHungerManager(HungerManager oldHungerManager){
        this.hungerManager = oldHungerManager;
    }
    public boolean damageJudgeForVC(DamageSource source){
        String damageName = source.name;
        return source instanceof EntityDamageSource||damageName.equals("cramming")||damageName.equals("cactus")||damageName.equals("fall")||damageName.equals("flyIntoWall")||damageName.equals("sweetBerryBush")||damageName.equals("stalagmite");
    }
    public void reallyAddExhaustion(float exhaustion,boolean needInput){
        if (!this.abilities.invulnerable && !this.world.isClient && this.hungerManager instanceof LishHungerManager lishHungerManager) {
            lishHungerManager.reallyAddExhaustion(exhaustion , needInput);
        }
    }

    protected float getJumpVelocity() {
        return (0.22F+ 2F*(float) (Objects.requireNonNull(this.getAttributeInstance(EntityAttributes.GENERIC_MOVEMENT_SPEED)).getBaseValue())) * super.getJumpVelocityMultiplier();
    }

    @Inject(method = "<init>" , at = @At("RETURN"))
    private void replaceHungerManagerInInit(CallbackInfo ci){
        this.hungerManager = new LishHungerManager();
    }

    @Inject(method = "getBlockBreakingSpeed", at = @At(value = "RETURN") , cancellable = true)
    private void addBlockBreakExh0015f(CallbackInfoReturnable<Float> cir) {
        this.reallyAddExhaustion(0.015F,false);
        if (this.hungerManager instanceof LishHungerManager lishHungerManager)cir.setReturnValue((cir.getReturnValueF() * (float) lishHungerManager.getMuscleEffect()));
    }

    @Inject(method = "jump", at = @At(value = "HEAD"))
    private void addWalkJumpExh005f(CallbackInfo ci) {
        if (this.isSprinting()) {
            this.reallyAddExhaustion(0.2F,false);
        } else {
            this.reallyAddExhaustion(0.05F,false);
        }
    }

    @Inject(method = "applyDamage" , at = @At(value = "INVOKE" , target = "Lnet/minecraft/entity/damage/DamageTracker;onDamage(Lnet/minecraft/entity/damage/DamageSource;FF)V"))
    private void damageMore(DamageSource source, float amount, CallbackInfo ci){
        this.reallyAddExhaustion(0.1f+ source.getExhaustion(),false);
        if (this.damageJudgeForVC(source) && this.hungerManager instanceof LishHungerManager manager && manager.getVC() < 100)this.addStatusEffect(new StatusEffectInstance(LishStatusEffects.BLEEDING, (int) (120f*amount),0));
    }

    @Inject(method = "attack", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;addExhaustion(F)V", shift = At.Shift.AFTER))
    private void addAttackExh01f(CallbackInfo ci) {
        this.reallyAddExhaustion(0.1F,false);
    }

    @Inject(method = "increaseRidingMotionStats" , at = @At(value = "INVOKE" , target = "Lnet/minecraft/entity/player/PlayerEntity;increaseStat(Lnet/minecraft/util/Identifier;I)V" , ordinal = 1))
    private void addBoatingExh0002f(CallbackInfo ci){
        if (this.getVehicle() !=null && (this.getVehicle().getPrimaryPassenger()) != null && this.getVehicle().getPrimaryPassenger().equals(this)) {
            this.reallyAddExhaustion(0.002F,true);
        }
    }

    @Inject(method = "increaseTravelMotionStats" , at = @At(value = "HEAD"))
    private void addTravelExhaustion(double dx, double dy, double dz, CallbackInfo ci){
        if (!this.hasVehicle()) {
            if (this.isSwimming()) {
                this.reallyAddExhaustion(0.004f,true);
            } else if (this.isSubmergedIn(FluidTags.WATER)) {
                this.reallyAddExhaustion(0.002f,true);
            } else if (this.isTouchingWater()) {
                this.reallyAddExhaustion(0.002f,true);
            } else if (this.isClimbing()) {
                this.reallyAddExhaustion(0.006f,true);
            } else if (this.onGround) {
                if (this.isSprinting()) {
                    this.reallyAddExhaustion(0.02f,true);
                } else if (this.isInSneakingPose()) {
                    this.reallyAddExhaustion(0.001f,true);
                } else {
                    this.reallyAddExhaustion(0.002f,true);
                }
            } else if (this.isFallFlying()) {
                this.reallyAddExhaustion(0.014f,false);
            }
        }
    }

}

